package geektime.concurrent.part3;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

public class SimpleCompletableFutureExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("****************runAsyncDemo******************");
        runAsyncDemo();
        System.out.println("****************supplyAsyncDemo******************");
        supplyAsyncDemo();
        System.out.println("****************thenRunDemo******************");
        thenRunDemo();
        System.out.println("****************thenAcceptDemo******************");
        thenAcceptDemo();
        System.out.println("****************thenApplyDemo******************");
        thenApplyDemo();
        System.out.println("****************thenComposeDemo******************");
        thenComposeDemo();
        System.out.println("****************thenCombineDemo******************");
        thenCombineDemo();
        System.out.println("****************whenCompleteDemo******************");
        whenCompleteDemo();

    }

    /**
     * runAsync()
     * FunctionalInterface: Runnable
     * lambda表达式中无参数，无返回值
     */
    private static void runAsyncDemo() {
        CompletableFuture.runAsync(() -> {
            System.out.println("runAsyncDemo() by: " + Thread.currentThread().getName());
        }).join();
    }

    /**
     * supplyAsync()
     * FunctionalInterface: Supplier
     * lambda表达式中无参数，有返回值
     */
    private static void supplyAsyncDemo() {
        String data = CompletableFuture.supplyAsync(() -> provideData()).join();
        System.out.println("supplyAsyncDemo() by: " + Thread.currentThread().getName());
    }

    public static String provideData() {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("provideData() by: " + Thread.currentThread().getName());
        return "provideData";
    }

    /**
     * thenRun()
     * FunctionalInterface: Runnable
     * lambda表达式中无参数，无返回值
     */
    private static void thenRunDemo() {
        CompletableFuture.runAsync(() -> System.out.println("thenRunDemo() by: " + Thread.currentThread().getName()))
            .thenRun(() -> System.out.println("thenRun() by: " + Thread.currentThread().getName())).join();
    }

    /**
     * thenAccept()
     * FunctionalInterface: Consumer
     * lambda表达式中有参数，无返回值
     */
    private static void thenAcceptDemo() {
        CompletableFuture.supplyAsync(() -> provideData()).thenAccept(data ->
            System.out.println("thenAccept() by: " + Thread.currentThread().getName() + ". thenAccept=" + data)
        ).join();
    }

    /**
     * thenApply()
     * FunctionalInterface: Function<? super T, ? extends U> fn
     * lambda表达式中有参数，有返回值
     */
    private static void thenApplyDemo() {
        String finalResult = CompletableFuture.supplyAsync(() -> provideData())
            .thenApply(data -> {
                System.out.println("thenApply() by: " + Thread.currentThread().getName());
                return "thenApply:" + data;
            }).join();
        System.out.println("thenApplyDemo() by: " + Thread.currentThread().getName() + ". finalResult=" + finalResult);
    }

    /**
     * thenCompose()
     * FunctionalInterface: Function<? super T, ? extends CompletionStage<U>>
     * lambda表达式中有参数，有返回值
     */
    private static void thenComposeDemo() {
        String thenComposeFinalResult = CompletableFuture.supplyAsync(() -> "then")
            .thenCompose(data -> CompletableFuture.supplyAsync(() -> data + "Compose")).join();
        System.out.println(thenComposeFinalResult);
        String thenApplyFinalResult = CompletableFuture.supplyAsync(() -> "then")
            .thenApply(data -> data + "Apply").join();
        System.out.println(thenApplyFinalResult);
    }

    /**
     * thenCompose()
     * FunctionalInterface:
     * CompletionStage<? extends U>
     * BiFunction<? super T, ? super U, ? extends V>
     * lambda表达式中有参数，有返回值
     */
    private static void thenCombineDemo() {
        String thenCombineFinalResult = CompletableFuture.supplyAsync(() -> "then")
            .thenCombine(CompletableFuture.supplyAsync(() -> "Combine"), (cf1, cf2) -> cf1 + cf2)
            .join();
        System.out.println(thenCombineFinalResult);
    }

    /**
     * whenComplete
     * FunctionalInterface: BiConsumer<? super T, ? super Throwable>
     * lambda表达式中有参数无返回值
     */
    private static void whenCompleteDemo() {
        CompletableFuture.supplyAsync(() -> {
            if (System.currentTimeMillis() % 2 == 0) return "whenComplete";
            throw new RuntimeException("奇数异常");
        })
            .whenComplete((data, th) -> {
                if (th == null) {
                    System.out.println(data);
                } else {
                    throw new RuntimeException(th);
                }
            }).join();
    }

}
